#pragma once
#include <iostream>
#include <memory>
#include <sys/epoll.h>
#include "Socket.hpp"

namespace wxd
{
#define FD_NUM 4096
    const int default_fd = -1;
    class EpollServer
    {
        static const int ready_array_num = 256;

    private:
    public:
        EpollServer(u_int16_t port)
            : _port(port), _listen_socket_ptr(std::make_unique<TcpSocket>(port))
        {
            // 创建epoll模型
            _epoll_fd = epoll_create(256);
            if (_epoll_fd < 0)
            {
                LOG(LogLevel::ERROR) << "epoll_create error!";
            }
            LOG(LogLevel::INFO) << "epoll_create success epoll_fd = " << _epoll_fd;
        }
        void Init()
        {
            // 完成创建socket,bind,listen
            _listen_socket_ptr->TcpSocketModule();
            // 将listensockfd添加到epoll模型中
            epoll_event events;
            events.data.fd = _listen_socket_ptr->Fd();
            events.events = EPOLLIN; // 关心读事件
            if (_epoll_fd > 0)
            {
                int n = epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, _listen_socket_ptr->Fd(), &events);
                if (n < 0)
                {
                    LOG(LogLevel::ERROR) << "epoll_ctl ADD error!";
                    return;
                }
                LOG(LogLevel::INFO) << "listensockfd into epoll success!";
            }
        }

        void Start()
        {
            // 调用poll帮助我们检测文件描述符是否就绪

            int timeout = -1; // ms
            while (true)
            {
                // 循环判断Epoll的等待结果
                int num = epoll_wait(_epoll_fd, _ready_events, ready_array_num, timeout);
                if (num > 0)
                {
                    // 派发任务
                    Dispatcher(num);
                }
                else if (num == 0)
                {
                    // 无就绪fd，继续
                    continue;
                }
                else
                {
                    // 出错
                    LOG(LogLevel::ERROR) << "epoll_wait error!";
                    return;
                }
            }
        }

        void Accepter()
        {
            InetAddrTrans client_trans;
            // 此时一定不会阻塞，读取新的连接
            int newfd = _listen_socket_ptr->Accept(client_trans);
            if (newfd < 0)
                return;
            LOG(LogLevel::INFO) << "收到一个连接[" << client_trans.AddrInfo() << "]";
            // 把连接添加进epoll模型
            struct epoll_event events;
            events.data.fd = newfd;
            events.events = EPOLLIN; // 关心读事件
            int n = epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, newfd, &events);
            if (n < 0)
            {
                LOG(LogLevel::ERROR) << "epoll_ctl ADD error!";
                return;
            }
            LOG(LogLevel::INFO) << "newfd into epoll success! newfd = " << newfd;
        }

        void Recv(int readfd)
        {
            char buffer[1024];
            int n = recv(readfd, buffer, sizeof(buffer) - 1, 0);
            // bug 暂没有考虑过读取完整性的问题 -> 应用层制定协议
            if (n > 0)
            {
                buffer[n] = 0;
                LOG(LogLevel::INFO) << "收到消息" << buffer;
                // 回显消息
                std::string message = "echo# ";
                message += buffer;
                send(readfd, message.c_str(), message.size(), 0); // bug暂未考虑过写条件是否就绪的问题，写Reactor的时候考虑
            }
            else if (n == 0)
            {
                LOG(LogLevel::INFO) << "客户端退出... fd = " << readfd;
                // 并从epoll模型中删除-再关闭客户端的文件描述符
                int n = epoll_ctl(_epoll_fd, EPOLL_CTL_DEL, readfd, nullptr);
                if (n < 0)
                {
                    LOG(LogLevel::ERROR) << "epoll_ctl DEL error!";
                    return;
                }
                LOG(LogLevel::INFO) << "delete fd success! fd = " << readfd;
                close(readfd);
            }
            else
            {
                LOG(LogLevel::ERROR) << "读取出错！";
    
                // 并从epoll模型中删除-再关闭客户端的文件描述符
                int n = epoll_ctl(_epoll_fd, EPOLL_CTL_DEL, readfd, nullptr);
                if (n < 0)
                {
                    LOG(LogLevel::ERROR) << "epoll_ctl DEL error!";
                    return;
                }
                LOG(LogLevel::INFO) << "delete fd success! fd = " << readfd;
                close(readfd);
                return;
            }
        }
       
    // 分派任务    
    void Dispatcher(int num)
    {
        // 处理就绪的文件描述符
        for (int i = 0; i < num; i++)
        {
            int ready_fd = _ready_events[i].data.fd;
            // 判断是否为listenfd
            if (ready_fd == _listen_socket_ptr->Fd())
            {
                // 处理Accept任务
                Accepter();
            }
            else
            {
                // 处理recv任务
                Recv(ready_fd);
            }
        }
    }

private:
    u_int16_t _port;
    std::unique_ptr<Socket> _listen_socket_ptr;
    int _epoll_fd;                                     // epoll模型的文件描述符
    struct epoll_event _ready_events[ready_array_num]; // 用于接收epoll返回结果的“数组”，把就绪队列中的内容取出，可设置成动态扩容的，这里先设置成固定的
};
}